/**
 * @file managesock.c
 * @brief Implementa le funzioni definite in managesock.h.
 *
 * Realizza un listener per ricevere le richieste di nuove sessioni socket e implementa
 * le funzioni per fornire i file descriptor per comunicare con le sessioni.
 *
 * @date Mar 11, 2012
 * @author Francesco Corvino
 */
#include "managesock.h"	/**< utilizzo delle definizioni e delle interfacce */
#include "interfacesock.h"	/**< inclusione per comunicare con i socket*/

#include "../../CHandler/inputHandler.h" /**< libreria per definire e aggiungere il filtro */
#include "../../logproxy/logproxy.h"	 /**< libreria per il logging */

static ConfigurationComm _MngFifo_config;

static InterfaceSock listenerSock;

pthread_t thListener;


/**
 * @brief Funzione che restituisce il file descriptor per una sessione socket.
 *
 * Al contrario delle fifo, i socket hanno solo un file descriptor che è sia in
 * lettura che in scrittura.
 *
 * @param data puntatore ai dati riguardanti l'instaurazione della sessione.
 * @return Restituisce il socket descriptor della sessione aperta.
 */
int MngSock_getSd(HiddenType* data){
	InterfaceSock* info = (InterfaceSock*) (data->hiddentype);
	return info->sd;
}

/**
 * @brief Chiude e libera la memoria allocata per la sessione socket.
 *
 * @param data struttura contenente le informazioni sulla sessione socket.
 */
void MngSock_close(HiddenType*data){
	InterfaceSock* info = (InterfaceSock*) (data->hiddentype);
	InterfaceSock_close(info);
}

void MngSock_configure(ConfigurationComm * config){
	memcpy(&_MngFifo_config, config, sizeof(ConfigurationComm));
}

/**
 * @brief Funzione che restituisce il file descriptor per il discovery di altre sessioni fifo.
 *
 * La funzione è privata poichè rientra nell'interfaccia di un oggetto @see Session
 * in particolare la funzione ricalca l'interfaccia della funzione getReadFd di questa struttura.
 *
 * @return intero che rappresenta il file descriptor da cui arriveranno le nuove richieste di sessione.
 */
int _MngSock_getFDMain(){ return listenerSock.sd;}

void * _mngSock_thListener(void * args){
	InterfaceSock infoChannel;
	while(1){
		InterfaceSock_waitReg(&listenerSock,&infoChannel);
		if(infoChannel.sd==-1){
			log_namedlevel(LOG_SOCKSESSION_NAME, LOG_ERROR_LEVEL,
					"Impossibile creare la fifo in input e/o output.");
		} else {
			log_namedlevel(LOG_SOCKSESSION_NAME,LOG_INFO_LEVEL,
					"Registra una nuova sessione");
		}

		/// - inizializza i valori di default della sessione
		HostSession* session = malloc(sizeof(HostSession));
		Session_init(session,MngSock_getSd,MngSock_getSd,NULL,MngSock_close);

		/// - salva le operazioni svolte
		HiddenType_init(&(session->dataSession),&infoChannel,sizeof(InterfaceSock));
		session->close = MngSock_close;

		/// - registra la nuova sessione
		(_MngFifo_config.registerSession)(session);

		/// - aggiorna le sessioni
		IH_updateInput();
	}
	return NULL;
}

/**
 * @brief funzione che gestisce la creazione della thread listener.
 */
void MngSock_startListener(){
	log_namedlevel(LOG_SOCKSESSION_NAME,LOG_INFO_LEVEL,
			"Attivazione Listner Socket!");

	/// - apre una socket di tipo server
	InterfaceSock_init(&listenerSock,getpid(),
			SOCKSESSION_MAINPORT,SOCKSESSION_SERVER);

	/// - controlla che il socket sia stato aperto correttamente
	if(listenerSock.sd < 0) {
		log_namedlevel(LOG_SOCKSESSION_NAME,LOG_ERROR_LEVEL,
				"Impossibile aprire il Listner Socket!");
		return ;
	}

	/// - avvia la thread di controllo
	if( pthread_create( &thListener, NULL, _mngSock_thListener, NULL)==-1){
		log_namedlevel(LOG_SOCKSESSION_NAME,LOG_ERROR_LEVEL,
				"Impossibile aprire il Listner Socket! (apertura della thread fallita)");
		return ;
	}
}

/**
 * @brief funzione pubblica che inizializza la Concrete Factory per le fifo.
 */
void MngSock_getFactoryDesc(ConcreteFactoryComm* factdesc){
	factdesc->configure = MngSock_configure;
	factdesc->startListen = MngSock_startListener;

	factdesc->getReadFD = MngSock_getSd;
	factdesc->getWriteFD = MngSock_getSd;
	factdesc->close = MngSock_close;
}
